package com.clementheliou.cheliou.web.util.cookie;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Component;

import com.clementheliou.cheliou.business.technical.security.authentication.model.AuthenticationDetails;
import com.clementheliou.cheliou.util.codec.binary.Base64Utils;
import com.clementheliou.cheliou.web.util.date.DateUtils;

/**
 * Utilities about the {@link Cookie}'s.
 * 
 * @author Clément HELIOU (clement.heliou@gmail.com)
 * @see {@link Component};
 * @see {@link Cookie}.
 * @since 1.0
 */
@Component
public class CookieUtils {

	/**
	 * The path to be used for the locale cookie.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @since 1.0
	 */
	private static final String LOCALE_COOKIE_PATH = "/";

	/**
	 * The prefix of the name that will be used for the locale cookie.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @since 1.0
	 */
	private static final String LOCALE_COOKIE_PREFIX = "cheliou-locale-";

	/**
	 * The separator to be used in the locale cookie value. By using it, we will
	 * able to split the value between the language part and the country one.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @since 1.0
	 */
	public static final String LOCALE_COOKIE_VALUE_SEPARATOR = "-";

	/**
	 * Creates the cookie that will store the locale selected by the given
	 * member. In the future, by reading this value, we will be able to guess
	 * the locale to use if this member is not yet connected. Please note that
	 * this value is encoded with the <i>Base64</i> algorithm.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @param member the member for which the locale is created.
	 * @param response the response to which the cookies will be add.
	 * @see {@link AuthenticationDetails}.
	 * @since 1.0
	 */
	public void createLocaleCookie(final AuthenticationDetails member, final HttpServletResponse response) {
		final Cookie localeCookie = new Cookie(getLocaleCookieNameFromMember(member), Base64Utils.encodeBase64(getLocaleCookieValueFromMember(member)));
		localeCookie.setMaxAge(DateUtils.SECONDS_PER_YEAR);
		localeCookie.setPath(LOCALE_COOKIE_PATH);

		response.addCookie(localeCookie);
	}

	/**
	 * Gets the cookie that stores the locale selected by the member using the
	 * browser. If no locale cookie is found, or more than one are found in the
	 * user's browser, <tt>null</tt> is returned.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @param request the request from which cookies are retrieved.
	 * @return the locale cookie if exists and is the only one locale cookie in
	 *         the user's browser, <tt>null</tt> otherwise.
	 * @since 1.0
	 */
	public Cookie getLocaleCookie(final HttpServletRequest request) {
		if (request.getCookies() == null) {
			return null;
		}

		final List<Cookie> cookies = new ArrayList<Cookie>();
		for (Cookie cookie : request.getCookies()) {
			if (cookie.getName().startsWith(LOCALE_COOKIE_PREFIX)) {
				cookies.add(cookie);
			}
		}

		return (cookies.size() == 1) ? cookies.get(0) : null;
	}

	/**
	 * Gets the name of the locale cookie for a given member.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @param member the member for which the locale cookie is created.
	 * @return the resulting cookie name.
	 * @see {@link AuthenticationDetails}.
	 * @since 1.0
	 */
	private String getLocaleCookieNameFromMember(final AuthenticationDetails member) {
		return LOCALE_COOKIE_PREFIX.concat(member.getMemberId().toString());
	}

	/**
	 * Gets the value of the locale cookie for a given member.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @param member the member for which the locale cookie is created.
	 * @return the resulting cookie value.
	 * @see {@link AuthenticationDetails}.
	 * @since 1.0
	 */
	private String getLocaleCookieValueFromMember(final AuthenticationDetails member) {
		return member.getMemberLocale().getLocale().getLanguage().concat(LOCALE_COOKIE_VALUE_SEPARATOR).concat(member.getMemberLocale().getLocale().getCountry());
	}
}
